use core::fmt::{self, Debug, Formatter};

use crate::config::{PAGE_SIZE, PAGE_SIZE_BITS};
use super::page_table::PageTableEntry;

// 先将地址和页号的概念抽象为 Rust 中的类型
// 借助 Rust 的类型安全特性来确保它们被正确实现
// (值得学习)

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PhysAddr(pub usize);

impl PhysAddr {
    pub fn page_offset(&self) -> usize {
        // 取低 12 位, 即: page offset
        self.0 & (PAGE_SIZE - 1)
    }

    pub fn floor(&self) -> PhysPageNum { // 向下取整
        PhysPageNum(self.0 / PAGE_SIZE)
    }

    pub fn ceil(&self) -> PhysPageNum { // 向上取整
        PhysPageNum((self.0 + PAGE_SIZE - 1) / PAGE_SIZE)
    }
    pub fn aligned(&self) -> bool { 
        self.page_offset() == 0 
    }
}

impl From<usize> for PhysAddr { // usize -> PhysAddr
    fn from(v: usize) -> Self { Self(v) }
}

impl From<PhysAddr> for usize { // PhysAddr -> usize
    fn from(v: PhysAddr) -> Self { v.0 }
}

impl From<PhysPageNum> for PhysAddr { // PhysPageNum -> PhysAddr
    fn from(v: PhysPageNum) -> Self {
        Self(v.0 << PAGE_SIZE_BITS) // 详见: (file:///./sv39-va-pa.png)
    }
}

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PhysPageNum(pub usize);

impl From<usize> for PhysPageNum { // usize -> PhysPageNum
    fn from(v: usize) -> Self { Self(v) }
}

impl From<PhysPageNum> for usize { // PhysPageNum -> usize
    fn from(v: PhysPageNum) -> Self { v.0 }
}

impl From<PhysAddr> for PhysPageNum {
    fn from(v: PhysAddr) -> Self { // PhysAddr -> PhysPageNum
        assert_eq!(v.page_offset(), 0); // 只有物理地址与页面大小对齐才能通过右移转换为物理页号
        v.floor()
    }
}

// 内核中访问物理页帧的方法
// 一个 物理页帧 对应 4096 个 byte 的空间
impl PhysPageNum {
    // 多级页表中每一个非叶节点都有 512 个页表项(PTE)
    // 一个节点为 512 * 8 = 4096 bytes, 刚好可以放在一个物理页帧中
    pub fn get_pte_array(&self) -> &'static mut [PageTableEntry] {
        let pa: PhysAddr = self.clone().into();
        unsafe {
            core::slice::from_raw_parts_mut(pa.0 as *mut PageTableEntry, 512)
        }
    }
    // 一个 物理页帧 对应 4096 个 byte 的空间
    pub fn get_bytes_array(&self) -> &'static mut [u8] {
        let pa: PhysAddr = self.clone().into();
        unsafe {
            core::slice::from_raw_parts_mut(pa.0 as *mut u8, 4096)
        }
    }
    // 获取一个恰好放在一个物理页帧开头的类型为 T 的数据的可变引用
    pub fn get_mut<T>(&self) -> &'static mut T {
        let pa: PhysAddr = self.clone().into();
        unsafe {
            (pa.0 as *mut T).as_mut().unwrap()
        }
    }
}

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct VirtAddr(pub usize);

impl From<usize> for VirtAddr {
    fn from(v: usize) -> Self { Self(v) }
}

impl From<VirtAddr> for usize {
    fn from(v: VirtAddr) -> Self { v.0 }
}

impl From<VirtAddr> for VirtPageNum {
    fn from(v: VirtAddr) -> Self {
        assert_eq!(v.page_offset(), 0);
        v.floor()
    }
}
impl From<VirtPageNum> for VirtAddr {
    fn from(v: VirtPageNum) -> Self { Self(v.0 << PAGE_SIZE_BITS) }
}

impl VirtAddr {
    pub fn floor(&self) -> VirtPageNum { 
        VirtPageNum(self.0 / PAGE_SIZE) 
    }
    pub fn ceil(&self) -> VirtPageNum  { 
        VirtPageNum((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE) 
    }
    pub fn page_offset(&self) -> usize { 
        self.0 & (PAGE_SIZE - 1) 
    }
    pub fn aligned(&self) -> bool { 
        self.page_offset() == 0 
    }
}


#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct VirtPageNum(pub usize);

impl From<usize> for VirtPageNum {
    fn from(v: usize) -> Self { Self(v) }
}

impl From<VirtPageNum> for usize {
    fn from(v: VirtPageNum) -> Self { v.0 }
}

impl Debug for VirtPageNum {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_fmt(format_args!("VPN: {:#x}", self.0))
    }
}

impl VirtPageNum {
    // 取出虚拟页号的三级页索引，并按照从高到低的顺序返回
    // 在多级页表上进行遍历，因此只取出低 27 位
    pub fn indexes(&self) -> [usize; 3] {
        let mut vpn = self.0;
        let mut idx = [0usize; 3];
        for i in (0..3).rev() {
            idx[i] = vpn & 511;
            vpn >>= 9;
        }
        idx // 页表三级索引
    }
}

pub trait StepByOne {
    fn step(&mut self);
}
impl StepByOne for VirtPageNum {
    fn step(&mut self) {
        self.0 += 1;
    }
}

#[derive(Copy, Clone)]
pub struct SimpleRange<T> where
    T: StepByOne + Copy + PartialEq + PartialOrd + Debug, {
    l: T,
    r: T,
}
impl<T> SimpleRange<T> where
    T: StepByOne + Copy + PartialEq + PartialOrd + Debug, {
    pub fn new(start: T, end: T) -> Self {
        assert!(start <= end, "start {:?} > end {:?}!", start, end);
        Self { l: start, r: end }
    }
    pub fn get_start(&self) -> T { self.l }
    pub fn get_end(&self) -> T { self.r }
}
impl<T> IntoIterator for SimpleRange<T> where
    T: StepByOne + Copy + PartialEq + PartialOrd + Debug, {
    type Item = T;
    type IntoIter = SimpleRangeIterator<T>;
    fn into_iter(self) -> Self::IntoIter {
        SimpleRangeIterator::new(self.l, self.r)
    }
}
pub struct SimpleRangeIterator<T> where
    T: StepByOne + Copy + PartialEq + PartialOrd + Debug, {
    current: T,
    end: T,
}
impl<T> SimpleRangeIterator<T> where
    T: StepByOne + Copy + PartialEq + PartialOrd + Debug, {
    pub fn new(l: T, r: T) -> Self {
        Self { current: l, end: r, }
    }
}
impl<T> Iterator for SimpleRangeIterator<T> where
    T: StepByOne + Copy + PartialEq + PartialOrd + Debug, {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        if self.current == self.end {
            None
        } else {
            let t = self.current;
            self.current.step();
            Some(t)
        }
    }
}
pub type VPNRange = SimpleRange<VirtPageNum>;